package com.yanqu.road.server.gameplayer.module.activity.feast;

import com.yanqu.road.entity.activity.feast.config.ShanHeFeastConfig;
import com.yanqu.road.entity.activity.feast.config.FeastEventConfig;
import com.yanqu.road.entity.activity.feast.data.FeastBattleCacheData;
import com.yanqu.road.entity.activity.feast.data.FeastBattleData;
import com.yanqu.road.entity.activity.feast.data.FeastBattleInfo;
import com.yanqu.road.entity.activity.feast.data.FeastBattleResult;
import com.yanqu.road.logic.helper.RandomWeightConfigHelper;
import com.yanqu.road.server.manger.activity.feast.ShanHeFeastMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.property.PropertyHelper;

import java.io.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class ShanHeFeastBattleScene implements Serializable {

    // 攻击者列表
    private List<FeastBattleData> attackList = new ArrayList<>();
    // 防御者列表
    private List<FeastBattleData> defenseList = new ArrayList<>();

    // 战斗序号
    private int battleNum = 0;
    // 战斗结果
    private Map<Integer, FeastBattleResult> resultMap = new ConcurrentHashMap<>();
    // 地图id
    private int missionId;
    //事件
    private int eventId;

    public int getBattleNum() {
        return battleNum;
    }

    public void setBattleNum(int battleNum) {
        this.battleNum = battleNum;
    }

    public FeastEventConfig getEventConfig() {
        return eventConfig;
    }

    public void setEventConfig(FeastEventConfig eventConfig) {
        this.eventConfig = eventConfig;
    }

    // 战斗时间
    private long battleTime;
    // 事件配置
    private FeastEventConfig eventConfig;

    ShanHeFeastBattleScene() {

    }

    public ShanHeFeastBattleScene deepCopyUsingSerialization()
    {
        try
        {
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            ObjectOutputStream o = new ObjectOutputStream(bo);
            o.writeObject(this);

            ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
            ObjectInputStream i = new ObjectInputStream(bi);

            return (ShanHeFeastBattleScene)i.readObject();
        }
        catch(Exception e)
        {
            return null;
        }
    }

    ShanHeFeastBattleScene(int missionId, int eventId, FeastEventConfig eventConfig) {
        this.missionId = missionId;
        this.eventId = eventId;
        this.battleTime = System.currentTimeMillis() / 1000;
        this.eventConfig = eventConfig;
    }

    // 获取战斗奖励
    public String getReward(int missionId, int eventId) {
        String rewards = null;
        if (this.missionId != missionId || this.eventId != eventId) {
            return rewards;
        }
        // TODO 容错
        Set<Integer> idSet = resultMap.keySet();
        if (idSet.size() == 0) {
            return rewards;
        }
        // 获取最后一次的攻击
        int maxId = Collections.max(idSet);
        FeastBattleResult resObj = resultMap.getOrDefault(maxId, null);
        if (null != resObj) {
            rewards = resObj.getReward();
        }
        return rewards;
    }

    public int getMissionId() {
        return missionId;
    }

    public void setMissionId(int missionId) {
        this.missionId = missionId;
    }

    public long getBattleTime() {
        return battleTime;
    }

    public void setBattleTime(long battleTime) {
        this.battleTime = battleTime;
    }

    // 攻击结果-指定目标
    public FeastBattleResult atkResult(FeastBattleData attackData, List<FeastBattleData> defenseList,
                                         boolean isBackAtk, int atkTime, int skillId) {
        isBackAtk = false;

        ShanHeFeastConfig config = ShanHeFeastMgr.getConfig();
        Random rBuilder = new Random();
        // 是否暴击
        boolean isCrit = false;
        // 是否晕眩
        boolean isStun = false;
        // 是否躲避
        boolean isDodge = false;
        // 吸血值
        long suckHp = 0;

        // 计算怒气值-时间产出怒气
        if (attackData.getType() == 1) {
            calcAngerValByConfig(attackData, atkTime, 0, 0, false);
        } else {
            calcAngerValByConfig(defenseList.get(0), atkTime, 0, 0, false);
        }

        List<FeastBattleInfo> resDefenseList = new ArrayList<>();
        boolean isOver = false;
        for (FeastBattleData defenseData : defenseList) {
            if (skillId == 0) {
                // 普攻才有暴击
                isCrit = rBuilder.nextInt(1000) <= (attackData.getCritRatio() - defenseData.getTenacity());
                // 普攻才会闪避
                int dodgeValue = (defenseData.getDodgeRatio() - attackData.getHitRatio());
                if(dodgeValue > config.getFEAST_MAX_SHANBI_SHANGXIAN()){
                    dodgeValue = config.getFEAST_MAX_SHANBI_SHANGXIAN();
                }
                isDodge = rBuilder.nextInt(1000) <= dodgeValue;
            }
            // 伤害值
            long harmValue = attackData.getAtk();
            if (skillId > 0) {
                // 获取技能伤害值
                harmValue = attackData.getSkillAtk();
            }
            // 暴击
            if (isCrit) {
                harmValue = harmValue * 2;
            }
            // 闪避
            if (isDodge) {
                harmValue = 0;
            }
            // 血量对比取最小值
            harmValue = Math.min(harmValue, defenseData.getHp());

            // 更新敌方血量
            defenseData.setHp(defenseData.getHp() - harmValue);

            // 计算怒气值-攻击产出怒气(普攻才产出怒气)
            if (attackData.getType() == 1 && skillId == 0) {
                calcAngerValByConfig(attackData, atkTime, harmValue, defenseData.getMaxHp(), true);
            }
            // 普攻才吸血
            if(skillId == 0) {
                // 吸血值
                suckHp += (long) Math.ceil(harmValue * (double)attackData.getSuckRatio()/1000);
            }

            // 防御者战斗信息
            FeastBattleInfo defenseInfoObj = new FeastBattleInfo(defenseData.getId(), harmValue, defenseData.getHp(), 0, isCrit, isStun, isDodge, defenseData.getAnger());
            resDefenseList.add(defenseInfoObj);

            if (defenseData.getHp() <= 0) {
                // 检测战斗是否结束
                if (checkGameOver(defenseData.getType())) {
                    isOver = true;
                    break;
                }
            }
        }
        // 更新进攻者吸血-血量上限值判断
        if ((attackData.getHp() + suckHp) > attackData.getMaxHp()) {
            suckHp = attackData.getMaxHp() - attackData.getHp();
        }
        attackData.setHp(attackData.getHp() + suckHp);

        attackData.setAtkTime(atkTime);

        if (skillId > 0) {
            // 扣除怒气值
            attackData.setAnger(attackData.getAnger() - config.getFEAST_PLAYER_SKILL_NEED_ANGER());
        }
        // 战斗序号
        battleNum++;
        // 攻击者信息
        FeastBattleInfo attackInfoObj = new FeastBattleInfo(attackData.getId(), 0, attackData.getHp(), suckHp, false, false, false, attackData.getAnger());
        // 生成战斗结果
        FeastBattleResult resultObj = new FeastBattleResult(battleNum, attackData.getType(), isBackAtk, skillId, attackInfoObj, resDefenseList);
        if (isOver) {
            resultObj.setWinner(attackData.getType());
            // 添加奖励
            if(attackData.getType() == 1) {
                resultObj.setReward(PropertyHelper.parsePropertyToString(RandomWeightConfigHelper.getProperty(eventConfig.getRewards())));
            }
        }
        // TODO 容错处理 战斗时长过长判断为失败
        if (atkTime > config.getFEAST_BATTLE_TIME() && !isOver) {
            resultObj.setWinner(2);
        }
        resultObj.setAtkTime(atkTime);
        // 缓存数据
        cacheBattleData(resultObj);

        return resultObj;
    }

    // 缓存战斗数据
    private void cacheBattleData(FeastBattleResult resultObj) {
        for (FeastBattleData battleData : attackList) {
            FeastBattleCacheData cacheObj = new FeastBattleCacheData(
                    battleData.getId(), battleData.getHp(), battleData.getAnger(), battleData.getAtkTime(), battleData.getLastCalcAngerTime()
            );
            resultObj.getCacheDataMap().put(cacheObj.getId(), cacheObj);

        }
        for (FeastBattleData battleData : defenseList) {
            FeastBattleCacheData cacheObj = new FeastBattleCacheData(
                    battleData.getId(), battleData.getHp(), battleData.getAnger(), battleData.getAtkTime(), battleData.getLastCalcAngerTime()
            );
            resultObj.getCacheDataMap().put(cacheObj.getId(), cacheObj);
        }
    }

    // 检测是否结束
    public boolean checkGameOver(int type) {
        List<FeastBattleData> tempList = defenseList;
        if (type == 1) {
            tempList = attackList;
        }
        for (FeastBattleData battleData : tempList) {
            if (battleData.getHp() > 0) {
                return false;
            }
        }
        return true;
    }

    // 获取攻击者(优先玩家)
    public FeastBattleData getAttacker() {
        // 取CD最小的
        int minNextTime = -1;
        FeastBattleData attacker = null;
        for (FeastBattleData battleData : attackList) {
            if (battleData.getHp() <= 0) {
                continue;
            }
            if (battleData.nextAtkTime() < minNextTime || minNextTime == -1) {
                minNextTime = battleData.nextAtkTime();
                attacker = battleData;
            }
        }
        for (FeastBattleData battleData : defenseList) {
            if (battleData.getHp() <= 0) {
                continue;
            }
            if (battleData.nextAtkTime() < minNextTime || minNextTime == -1) {
                minNextTime = battleData.nextAtkTime();
                attacker = battleData;
            }
        }
        return attacker;
    }

    // 获取技能攻击者
    public FeastBattleData getSkillAttacker() {
        for (FeastBattleData battleData : attackList) {
            if (battleData.getSkillId() > 0) {
                return battleData;
            }
        }
        return null;
    }

    // 获取防御者
    public FeastBattleData getDefender(int type, int id) {
        List<FeastBattleData> tempList = defenseList;
        if (type == 2) {
            tempList = attackList;
        }
        FeastBattleData defender = null;
        for (FeastBattleData battleData : tempList) {
            if (battleData.getHp() <= 0) {
                continue;
            }
            if (defender == null || defender.getAtk() < battleData.getAtk()) {
                defender = battleData;
            }
            // 选中目标
            if (id > 0  && type == 1) {
                if(battleData.getId() == id) {
                    return battleData;
                }
            }
        }
        return defender;
    }

    // 重置战场数据
    private void resetBattleScene(int battleNum) {
        FeastBattleResult resObj = resultMap.getOrDefault(battleNum, null);
        if (null == resObj) {
            return;
        }
        // 攻击者
        for (FeastBattleData battleData : attackList) {
            resetBattleData(resObj, battleData);
        }
        for (FeastBattleData battleData : defenseList) {
            resetBattleData(resObj, battleData);
        }
        // 清除数据
        this.battleNum=battleNum;
        this.resultMap.clear();
    }
    // 重置战斗数据
    private void resetBattleData(FeastBattleResult resObj, FeastBattleData battleData) {
        FeastBattleCacheData cacheData = resObj.getCacheDataMap().get(battleData.getId());
        battleData.setHp(cacheData.getHp());
        battleData.setAnger(cacheData.getAnger());
        battleData.setAtkTime(cacheData.getAtkTime());
        battleData.setLastCalcAngerTime(cacheData.getLastCalcAngerTime());
    }
    /**
     *  生成战斗结果-释放技能
     */
    public int skillOpen(ShanHeFeastConfig config, int battleNum) {
        FeastBattleResult resObj = resultMap.getOrDefault(battleNum, null);
        if (null == resObj && battleNum != 0) {
            return GameErrorCode.E_XIU_XIAN_PARAM_ERROR;
        }
        if (battleNum > 0) {
            // 重置战斗数据
            resetBattleScene(battleNum);
        }
        // 检测怒气值
        FeastBattleData attacker = getSkillAttacker();
        if (attacker.getAnger() < config.getFEAST_PLAYER_SKILL_NEED_ANGER() || attacker.getSkillId() == 0) {
            return GameErrorCode.E_XIU_XIAN_SKILL_ANGER_LIMIT;
        }
        if (checkGameOver(2)) {
            return GameErrorCode.E_XIU_XIAN_BATTLE_HAS_OVER;
        }
        // 攻击时间
        int atkTime = attacker.nextAtkTime();
        if (resObj != null) {
            atkTime = resObj.getAtkTime();
        }
        // 战斗结果
        FeastBattleResult result = atkResult(attacker, defenseList, false, atkTime, attacker.getSkillId());
        resultMap.put(result.getBattleNum(), result);

        if (result.getWinner() > 0) {
            return 0;
        }
        buildBattleResult(0);
        return 0;
    }
    /**
     *  生成战斗结果-选中Npc
     */
    public int selectNpc(int id, int battleNum) {
        // 获取当时的战斗结果
        FeastBattleResult resObj = resultMap.getOrDefault(battleNum, null);
        if (null == resObj) {
//            ShanHeFeastMgr.getLogger().warn("id:{},battleNum:{},选择失败", id, battleNum);
            return GameErrorCode.E_XIU_XIAN_BATTLE_HAS_OVER;
        }
        // 重置战斗数据
        resetBattleScene(battleNum);
        if (checkGameOver(2)) {
            return GameErrorCode.E_XIU_XIAN_BATTLE_HAS_OVER;
        }
        buildBattleResult(id);
        return 0;
    }
    /**
     *  生成战斗结果-正常攻击
     */
    public void buildBattleResult(int selectId) {
        for (int i = 0; i < 999999; i++) {
            // 获取攻击者
            FeastBattleData attacker = getAttacker();
            if (null == attacker) {
                continue;
            }
            int time = attacker.nextAtkTime();
            // 锁定目标
            FeastBattleData defender = getDefender(attacker.getType(), selectId);
            List<FeastBattleData> curDefenseList = new ArrayList<>();
            curDefenseList.add(defender);

            // 开始攻击
            FeastBattleResult result = atkResult(attacker, curDefenseList, false, time, 0);
            resultMap.put(result.getBattleNum(), result);
            if (result.getWinner() > 0) {
                return;
            }

            //技能满了
            ShanHeFeastConfig config = ShanHeFeastMgr.getConfig();
            if (attacker.getAnger() >= config.getFEAST_PLAYER_SKILL_NEED_ANGER() && attacker.getSkillId() > 0) {
                // 战斗结果
                result = atkResult(attacker, defenseList, false, time, attacker.getSkillId());
                resultMap.put(result.getBattleNum(), result);

                if (result.getWinner() > 0) {
                    return;
                }
            }
        }
    }
    /**
     * 计算怒气值
     * 1、时间增加怒气值 2、攻击造成伤害怒气值
     **/
    private int calcAngerValByConfig(FeastBattleData attackData, int atkTime, long harmValue, long maxHp, boolean isAttack) {
        int angerVal = 0;
        if (attackData.getSkillId() <= 0) {
            return angerVal;
        }
        ShanHeFeastConfig config = ShanHeFeastMgr.getConfig();
        String[] angerArray = config.getFEAST_PLAYER_ANGER_PRM().split("\\|");
        if (angerArray.length < 4) {
            return angerVal;
        }
        // 攻击产生的怒气
        if (isAttack) {
            angerVal += (int)((double)harmValue / maxHp * Integer.parseInt(angerArray[2]) / 1000d * Integer.parseInt(angerArray[3]));
        } else {
            // 时间恢复的怒气
            int recoverCd = Integer.parseInt(angerArray[0]);
            int addCount = atkTime / recoverCd - attackData.getLastCalcAngerTime() / recoverCd;
            if (addCount > 0) {
                angerVal += addCount * Integer.parseInt(angerArray[1]);
                // 设置新的恢复时间
                attackData.setLastCalcAngerTime(attackData.getLastCalcAngerTime() + addCount * recoverCd);
            }
        }
        angerVal = Math.min(angerVal, config.getFEAST_PLAYER_SKILL_MAX_ANGER() - attackData.getAnger());
        attackData.setAnger(attackData.getAnger() + angerVal);
        return angerVal;
    }

    public Map<Integer, FeastBattleResult> getResultMap() {
        return resultMap;
    }

    public void setResultMap(Map<Integer, FeastBattleResult> resultMap) {
        this.resultMap = resultMap;
    }

    public List<FeastBattleData> getAttackList() {
        return attackList;
    }

    public void setAttackList(List<FeastBattleData> attackList) {
        this.attackList = attackList;
    }

    public List<FeastBattleData> getDefenseList() {
        return defenseList;
    }

    public void setDefenseList(List<FeastBattleData> defenseList) {
        this.defenseList = defenseList;
    }

    public int getEventId() {
        return eventId;
    }

    public void setEventId(int eventId) {
        this.eventId = eventId;
    }
}
